﻿using System;
using CxExtension;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using JetBrains.Annotations;
using UnityExtensions;

namespace UnityEngine
{
	[Flags]
	public enum FitterTypeE
	{
		None = 0x0,
		Horizontal = 0x1,
		Vertical = 0x2,
		All = 0x3,
	}
	public static class TransformExtUGUI
	{
		#region CanvasGroup


		public static void SetCanvasGroupAlpha(this Transform self,float alpha)
		{
			self.GetComponent<CanvasGroup>(it => it.alpha = alpha);
		}


		#endregion
		#region CircleLayoutGroup


		public static void SetCircleLayoutGroupLayoutBySlice(this Transform self, int sliceNum)
		{
			self.GetComponent<CircleLayoutGroup>(it => it.SetLayoutBySlice(sliceNum));
		}

		public static void SetCircleLayoutGroupStartAngle(this Transform self, float angle)
		{
			self.GetComponent<CircleLayoutGroup>(it => it.StartAngle = angle);
		}


		#endregion
		#region SliderIntOffsetBar

		public static void SetSliderIntOffsetBarValueChangeEvent(this Transform self,
			UnityAction<Transform, float> action)
		{
			self.SetSliderIntOffsetBarValueChangeEvent(it => action(self, it));
		}
		public static void SetSliderIntOffsetBarValueChangeEvent(this Transform self, UnityAction<float> action)
		{
			self.GetComponent<SliderIntOffsetBar>(it =>
			{
				it.onValueChanged.RemoveAllListeners();
				it.onValueChanged.AddListener(action);
			});

		}
		public static void SetSliderIntOffsetBarMinValue(this Transform self, float value)
		{
			self.GetComponent<SliderIntOffsetBar>(it => it.SetMinValue(value));
		}
		public static void SetSliderIntOffsetBarButtonDisableAction(this Transform self, Action<Transform,bool> value)
		{
			self.GetComponent<SliderIntOffsetBar>(it => it.SetButtonDisableAction(value));
		}
		public static void SetSliderIntOffsetBarMaxValue(this Transform self, float value)
		{
			self.GetComponent<SliderIntOffsetBar>(it => it.SetMaxValue(value));
		}
		public static void SetSliderIntOffsetBarValue(this Transform self, float value)
		{
			self.GetComponent<SliderIntOffsetBar>(it => it.SetCurrentValue(value));
		}
		public static float GetSliderIntOffsetBarValue(this Transform self)
		{
			float v = 0;
			self.GetComponent<SliderIntOffsetBar>(it => v = it.Value);
			return v;
		}
		public static void SetSliderIntOffsetBarStep(this Transform self, float value)
		{
			self.GetComponent<SliderIntOffsetBar>(it => it.SetStep(value));
		}

		#endregion
		#region EventTrigger

		public static void GetEventTriggerEntry([NotNull] this Transform self, EventTriggerType triggerType,
			[NotNull] Action<EventTrigger.Entry> call)
		{
			if (self == null) throw new ArgumentNullException("self");
			if (call == null) throw new ArgumentNullException("call");

			self.GetComponent<EventTrigger>(it =>
			   {
				   var entry = it.triggers.GetOrNew(it1 => it1.eventID == triggerType,
					   () => new EventTrigger.Entry()
					   {
						   eventID = triggerType
					   });
				   call(entry);

			   });
		}

		public static void SetEventTriggerEvent([NotNull] this Transform self, EventTriggerType triggerType,
			[NotNull] UnityAction<BaseEventData> callback)
		{
			if (callback == null) throw new ArgumentNullException("callback");
			self.GetEventTriggerEntry(triggerType, it =>
			{
				it.callback.RemoveAllListeners();
				it.callback.AddListener(callback);
			});
		}
		public static void AddEventTriggerEvent([NotNull] this Transform self, EventTriggerType triggerType,
			[NotNull] UnityAction<BaseEventData> callback)
		{
			if (callback == null) throw new ArgumentNullException("callback");
			self.GetEventTriggerEntry(triggerType, it =>
			 {
				 it.callback.AddListener(callback);
			 });
		}

		public static void RemoveAllEventTriggerListener([NotNull] this Transform self, EventTriggerType triggerType)
		{
			self.GetEventTriggerEntry(triggerType, it =>
			{
				it.callback.RemoveAllListeners();
			});
		}

		#endregion
		#region Slider


		public static void SetSliderValueChangeEvent1(this Transform self, UnityAction<Transform, float> action)
		{
			self.SetSliderValueChangeEvent((arg0 => action(self, arg0)));
		}

		public static void SetSliderValueChangeEvent(this Transform self, UnityAction<float> action)
		{
			self.GetComponent<Slider>(it =>
			{
				it.onValueChanged.RemoveAllListeners();
				it.onValueChanged.AddListener(action);
			});
		}

		public static float GetSliderValue(this Transform self)
		{
			var value = 0f;
			self.GetComponent<Slider>(it => value = it.value);
			return value;
		}
		public static float GetSliderNormalizedValue(this Transform self)
		{
			var value = 0f;
			self.GetComponent<Slider>(it => value = it.normalizedValue);
			return value;
		}

		public static void SetSliderValue(this Transform self, float value)
		{
			self.GetComponent<Slider>(it => it.value = value);
		}
		public static void SetSliderMaxValue(this Transform self, float value)
		{
			self.GetComponent<Slider>(it => it.maxValue = value);
		}
		public static void SetSliderMinValue(this Transform self, float value)
		{
			self.GetComponent<Slider>(it => it.minValue = value);
		}
		public static void SetSliderNormalizedValue(this Transform self, float value)
		{
			self.GetComponent<Slider>(it => it.normalizedValue = value);
		}/// <summary>
		 /// 反转位置Y
		 /// </summary>
		 /// <param name="self"></param>
		#endregion

		#region InputText

		public static void SetInputText(this Transform self, string text)
		{
			self.GetComponent<InputField>(it => it.text = text);
		}
		public static string GetInputText(this Transform self)
		{
			var com = self.GetComponent<InputField>();
			if (com == null)
			{
				Debug.LogErrorFormat("{0}上面没有{1}组件", self.name, typeof(InputField).Name); return string.Empty;
			}

			return com.text;
		}

		#endregion

		#region Toggle

		/// <summary>
		/// 
		/// </summary>
		/// <param name="self"></param>
		/// <param name="index">lua index start with 1</param>
		/// <param name="isOn"></param>
		/// <param name="forceSendChangeEvent"></param>
		public static void SetActiveToggleChildLua(this Transform self, int index, bool isOn, bool forceSendChangeEvent = false)
		{
			self.SetActiveToggleChild(index - 1, isOn,forceSendChangeEvent);
		}
		public static void SetActiveToggleChild(this Transform self, int index, bool isOn,bool forceSendChangeEvent = false)
		{
			var item = self.GetChild(index);
			if (item)
			{
				item.GetComponent<Toggle>(it =>
				{
					var isSample = it.isOn == isOn;
					it.isOn = isOn;
					if (isSample && forceSendChangeEvent)
					{
						it.onValueChanged.Invoke(isOn);
					}
					else
					{
						if (it.isActiveAndEnabled == false && it.group != null)
						{
							it.group.NotifyToggleOn(it);
						}
					}
				});
			}
		}


		public static void AddChildAllToggleValueChangeEvent(this Transform self, UnityAction<bool> action)
		{
			self.ForEachChild((transform => transform.AddToggleValueChangeEvent(action)));
		}
		public static void SetChildAllToggleValueChangeEvent(this Transform self, UnityAction<bool> action)
		{
			self.ForEachChild((transform => transform.SetToggleValueChangeEvent(action)));
		}
		public static void AddToggleValueChangeEvent(this Transform self, UnityAction<bool> action)
		{
			self.GetComponent<Toggle>(it => it.onValueChanged.AddListener(action));
		}
		public static void SetToggleValueChangeEvent(this Transform self, UnityAction<bool> action)
		{
			self.GetComponent<Toggle>(it =>
			{
				it.onValueChanged.RemoveAllListeners();
				it.onValueChanged.AddListener(action);
			});
		}
		public static void SetToggleValue(this Transform self, bool value)
		{
			self.GetComponent<Toggle>(it => it.isOn = value);
		}
		public static bool GetToggleValue(this Transform self)
		{
			var value = false;
			self.GetComponent<Toggle>(it => value = it.isOn);
			return value;
		}

		public static void SetToggleRevert(this Transform self)
		{
			self.GetComponent<Toggle>(it => it.isOn = !it.isOn);
		}
		/// <summary>
		/// 添加开关改变事件
		/// </summary>
		/// <param name="self"></param>
		/// <param name="item"></param>
		/// <param name="call"></param>
		public static void AddToggleClick(this Transform self, UnityAction<bool> call)
		{
			self.GetComponent<Toggle>(it => it.onValueChanged.AddListener(call));
		}
		/// <summary>
		/// 为groups添加一个toggle
		/// </summary>
		/// <param name="self"></param>
		/// <param name="item"></param>
		public static void AddToggle(this Transform self, Transform item)
		{
			ToggleGroup parent = null;
			Toggle toggle = null;
			self.GetComponent<ToggleGroup>(it => parent = it);
			item.GetComponent<Toggle>(it => toggle = it);
			if (toggle == null || parent == null)
			{
				return;
			}
			toggle.group = parent;
		}

		#endregion

		#region Graphic

		public static void SetLayoutDirty(this Transform self)
		{
			self.GetComponent<Graphic>(it => it.SetLayoutDirty());

		}
		public static void SetOutlineColor(this Transform self, Color color)
		{
			var com = self.GetComponent<Outline>();
			if (com)
			{
				com.effectColor = color;
			}
		}
		public static void SetColor(this Transform self, Color color)
		{
			var com = self.GetComponent<Graphic>();
			if (com)
			{
				com.color = color;
			}
		}
		public static Color GetColor(this Transform self)
		{
			var com = self.GetComponent<Graphic>();
			return com ? com.color : Color.white;
		}
		#endregion

		#region RectTransform

		/// <summary>
		/// 设置为最佳尺寸
		/// 会遍历当前所有的LayoutElement,慎用
		/// </summary>
		/// <param name="self"></param>
		/// <param name="setAllMax">如果为false 设置为首个ILayoutElement的Preferred
		/// true 会遍历当前所有的LayoutElement,选取最佳,慎用</param>
		public static void SetPreferredSize(this Transform self, bool setAllMax = false)
		{
			if (self == null) throw new ArgumentNullException("self");
			self.GetComponent<RectTransform>(transf =>
			{
				var axis = RectTransform.Axis.Vertical;
				transf.SetSizeWithCurrentAnchors(axis, transf.GetPreferredSize((int)axis, setAllMax));
				axis = RectTransform.Axis.Horizontal;
				transf.SetSizeWithCurrentAnchors(axis, transf.GetPreferredSize((int)axis, setAllMax));
			});
		}

		/// <summary>
		/// 设置为最佳高度
		/// 会遍历当前所有的LayoutElement,慎用
		/// </summary>
		/// <param name="self"></param>
		/// <param name="setAllMax">如果为false 设置为首个ILayoutElement的Preferred
		/// true 会遍历当前所有的LayoutElement,选取最佳,慎用</param>
		public static void SetPreferredHeight(this Transform self, bool setAllMax = false)
		{
			if (self == null) throw new ArgumentNullException("self");
			self.GetComponent<RectTransform>(transf =>
			{
				var axis = RectTransform.Axis.Vertical;
				transf.SetSizeWithCurrentAnchors(axis, transf.GetPreferredSize((int)axis, setAllMax));
			});
		}

		/// <summary>
		/// 设置为最佳宽度
		/// </summary>
		/// <param name="self"></param>
		/// <param name="setAllMax">如果为false 设置为首个ILayoutElement的Preferred
		/// true 会遍历当前所有的LayoutElement,选取最佳,慎用</param>
		public static void SetPreferredWidth(this Transform self,bool setAllMax = false)
		{
			if (self == null) throw new ArgumentNullException("self");
			self.GetComponent<RectTransform>(transf =>
			{
				var axis = RectTransform.Axis.Horizontal;
				transf.SetSizeWithCurrentAnchors(axis, transf.GetPreferredSize((int)axis,setAllMax));
			});
		}

		public static float GetPreferredSize(this RectTransform self,int axis, bool setAllMax = false)
		{
			if (setAllMax)
			{
				return LayoutUtility.GetPreferredSize(self, axis);
			}

			var element = self.GetComponent<ILayoutElement>();
			var value = 0f;
			if (element != null)
			{
				value = axis == 0 ? element.preferredWidth : element.preferredHeight;
			}

			return value;
		}
		public static void SetLayoutGroupActive(this Transform self, string child, bool active)
		{
			self.Find(child, it => it.SetLayoutGroupActive(active));
		}

		public static void SetLayoutGroupAndFitterActive([NotNull] this Transform self, bool active)
		{
			self.SetLayoutGroupActive(active);
			self.SetContentSizeFitterActive(active);
		}

		public static void SetLayoutGroupActive([NotNull] this Transform self, bool active)
		{
			if (self == null) throw new ArgumentNullException("self");
			self.GetComponent<LayoutGroup>((group => group.enabled = active));
		}
		public static void SetContentSizeFitterActive([NotNull] this Transform self, bool active)
		{
			if (self == null) throw new ArgumentNullException("self");
			self.GetComponent<ContentSizeFitter>((group => group.enabled = active));
		}


		public static void ForceRebuildParentLayoutImmediate([NotNull] this Transform self)
		{
			if (self == null) throw new ArgumentNullException("self");
			var parent = self.parent;
			if (parent)
			{
				parent.ForceRebuildLayoutImmediate();
			}
		}

		public static void ForceRebuildLayoutImmediate(this Transform self)
		{
			self.GetComponent<RectTransform>(LayoutRebuilder.ForceRebuildLayoutImmediate);
		}
		public static void LayoutRebuildDirect(this Transform self)
		{
			self.GetComponent<ICanvasElement>(CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild);
		}

		public static void MarkLayoutForRebuild(this Transform self)
		{
			self.GetComponent<RectTransform>(LayoutRebuilder.MarkLayoutForRebuild);
		}


		public static void RevertY(this RectTransform self)
		{
			var newpos = self.anchoredPosition3D;
			newpos.y = -newpos.y;
			self.anchoredPosition3D = newpos;
		}

		/// <summary>
		/// 反转位置Y
		/// </summary>
		/// <param name="self"></param>
		/// <param name="up">true 表示强制正数,false表示强制负数</param>
		public static void ForceY(this RectTransform self, bool up)
		{
			var newpos = self.anchoredPosition3D;
			var y = Mathf.Abs(newpos.y);
			newpos.y = up ? y : -y;
			self.anchoredPosition3D = newpos;
		}

		/// <summary>
		/// set position and fitter in target rect
		/// </summary>
		/// <param name="self"></param>
		/// <param name="pos"></param>
		/// <param name="rectFitter"></param>
		/// <param name="fitter">0 x,1 y,3 all</param>
		/// <returns></returns>
		public static bool SetUiPositionFitterInRect(this Transform self, Vector2 pos, Rect rectFitter, FitterTypeE fitter)
		{
			var rectTransf = self as RectTransform;
			var posOffset = pos - rectTransf.anchoredPosition;
			//var alis = sFourCornersArray;
			var result = true;
			var rect = rectTransf.GetRectInParentSpace();

			var posMax = rectFitter.size - rectTransf.sizeDelta;
			var posRect = new Rect(Vector2.zero, posMax);

			var oldPos = rect.position;
			var newPos1 = oldPos + posOffset;

			if (fitter.HasFlag(FitterTypeE.Horizontal) && rectFitter.width >= rect.width)
			{/*(fitter & FitterTypeE.Horizontal)*/
				newPos1 = posRect.ClampAxis(newPos1, 0);
			}
			if (fitter.HasFlag(FitterTypeE.Vertical) && rectFitter.height >= rect.height)
			{/*(fitter == FitterTypeE.Vertical || fitter == FitterTypeE.All)*/
				newPos1 = posRect.ClampAxis(newPos1, 1);
			}

			rectTransf.anchoredPosition = rectTransf.anchoredPosition + (newPos1 - oldPos);
			return result;
		}

	
		/// <summary>
		/// set ugui position and fitter ui rect in parent size rect
		/// </summary>
		/// <param name="self"></param>
		/// <param name="pos"></param>
		/// <param name="fitter"></param>		
		public static void SetUiPositionFitterInParentRect(this Transform self, Vector2 pos, FitterTypeE fitter)
		{
			var parent = self.parent as RectTransform;
			if (parent != null)
			{
				var rect = new Rect(Vector2.zero,parent.sizeDelta);
				self.SetUiPositionFitterInRect(pos,rect,fitter);
			}
		}

		public static void SetUiWidth(this Transform self, float width)
		{
			self.GetComponent<RectTransform>(it => it.sizeDelta = new Vector2(width, it.sizeDelta.y));
		}

		public static Vector2 GetUiSize(this Transform self)
		{
			RectTransform trasf = null;
			self.GetComponent<RectTransform>(it => trasf = it);
			return trasf ? trasf.sizeDelta : Vector2.zero;
		}

    
        public static Vector4 GetUiRect(this Transform self)
        {
            RectTransform trasf = self.GetComponent<RectTransform>();
            return new Vector4(trasf.rect.x,trasf.rect.y,trasf.rect.width,trasf.rect.height);
        }

		public static float GetUiSize(this Transform self, int axis)
		{
			var size = self.GetUiSize();
			return size[axis];
		}
		public static float GetUiHeight(this Transform self)
		{
			return self.GetUiSize(1);
		}
		public static float GetUiWidth(this Transform self)
		{
			return self.GetUiSize(0);
		}
		public static void SetUiHeight(this Transform self, float height)
		{
			self.GetComponent<RectTransform>(it => it.sizeDelta = new Vector2(it.sizeDelta.x, height));
		}
		public static void SetUiSize(this Transform self, Vector2 size)
		{
			self.GetComponent<RectTransform>(it => it.sizeDelta = size);
		}

		public static void SetUiPosition(this Transform self, Vector2 pos)
		{
			self.GetComponent<RectTransform>(it => it.anchoredPosition = pos);
		}

		public static Vector2 GetUiPosition(this Transform self)
		{
			var pos = Vector2.zero;
			self.GetComponent<RectTransform>(it => pos = it.anchoredPosition);
			return pos;
		}
		#endregion

		#region Selectable

		public static void SetSelectableInteractable(this Transform self, bool value)
		{
			self.GetComponent<Selectable>(it => it.interactable = value);

		}



		#endregion

		#region Button
		public static void SetButtonActive(this Transform self, bool value)
		{
			self.GetComponent<Button>(it => it.enabled = value);
		}
		public static void SetButtonInteractable(this Transform self, bool value)
		{
			self.SetSelectableInteractable(value);
		}

		public static void ClearButtonClickListener(this Transform self)
		{
			self.GetComponent<Button>(it => it.onClick.RemoveAllListeners());

		}
		/// <summary>
		/// 获取某个组件 如果成功 回调函数
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="self"></param>
		/// <param name="action"></param>
		/// <summary>
		/// 查找指定名称的 子节点 获取 Button组件 添加点击事件
		/// 中途任意环节 返回null就返回执行
		/// </summary>
		/// <param name="self"></param>
		/// <param name="childname"></param>
		/// <param name="action"></param>
		public static void AddButtonClickListener(this Transform self, string childname, UnityAction action)
		{
			self.Find(childname, it => it.AddButtonClickListener(action));
		}

		/// <summary>
		/// 获取Button组件 设置onClick
		/// </summary>
		/// <param name="self"></param>
		/// <param name="action"></param>
		public static void AddButtonClickListener(this Transform self, UnityAction action)
		{
			self.GetComponent<Button>(it => it.onClick.AddListener(action));
		}
		public static void SetButtonClickEvent(this Transform self, UnityAction action)
		{
			self.GetComponent<Button>(it =>
			{
				it.onClick.RemoveAllListeners();
				it.onClick.AddListener(action);
			});
		}

		public static void SetButtonClickEvent1(this Transform self, UnityAction<Transform> action)
		{
			self.SetButtonClickEvent((() => action(self)));
		}
		#endregion

		#region Text
		public static void SetTextPreferredWidth(this Transform self, string childName, string text)
		{
			self.Find(childName, it =>
			{
				it.SetText(text);
				it.SetPreferredWidth();
			});
		}
		public static void SetTextPreferredWidth(this Transform self, string text)
		{
			self.SetText(text);
			self.SetPreferredWidth();
		}

		public static void SetTextRate(this Transform self, float left, float right)
		{
			var str = string.Format("{0}/{1}", left, right);

			self.SetText(str);
		}
		/// <summary>
		/// 取得Text组件 并设置text
		/// </summary>
		/// <param name="self"></param>
		/// <param name="text"></param>
		public static void SetText(this Transform self, string text)
		{
			self.GetComponent<Text>(it => it.text = text);
		}

		/// <summary>
		/// 查找指定名称的子节点 然后获取Text组件 并设置其text
		/// 如果中途任意环节返回为null会显示日志 并返回
		/// </summary>
		/// <param name="self"></param>
		/// <param name="childName"></param>
		/// <param name="text"></param>
		public static void SetText(this Transform self, string childName, string text)
		{
			self.Find(childName, it => it.SetText(text));
		}

		#endregion

		#region Image
		public static void SetImageEnable(this Transform self, bool enabled)
		{
			self.GetComponent<Image>(it => it.enabled = enabled);
		}

		public static void SetSprite(this Transform self, Sprite sprite)
		{
			self.GetComponent<Image>(it => it.sprite = sprite);
		}

		public static void SetSprite(this Transform self, string childname, Sprite sprite)
		{
			self.Find(childname, it => it.SetSprite(sprite));
		}

#if false

		public static bool SetSpriteByAtlasPrefixAndIndex(this Transform self, SpriteAtlas atlas, string prefix, int index)
		{
			var str = string.Format("{0}{1}", prefix, index);
			return self.SetSpriteByAtlas(atlas, str);
		}

		public static bool SetSpriteByAtlasPrefixAndIndex(this Transform self, string childName, SpriteAtlas atlas,
			string prefix, int index)
		{
			var re = false;
			self.Find(childName, (transform => re = transform.SetSpriteByAtlasPrefixAndIndex(atlas, prefix, index)));
			return re;

		}


		public static bool SetSpriteByAtlas(this Transform self, string childName, SpriteAtlas atlas, string name)
		{
			var re = false;

			self.Find(childName, transform => re = transform.SetSpriteByAtlas(atlas, name));
			return re;
		}
		public static bool SetSpriteByAtlas(this Transform self, SpriteAtlas atlas, string name)
		{
			if (atlas == null) { return false; }
			var sprite = atlas.GetSprite(name);
			if (sprite == null)
			{
				//var relativeTransform = self.Get;
				Debug.LogErrorFormat("{0}没有找到sprite:{1},transform Path:{2}", atlas.name, name, self.GetTransformPath());
				return false;
			}
			self.SetSprite(sprite);
			return true;
		}

#endif
		#endregion

	}
}